package com.glsc.ngateway.opmanage.amqp.receiver;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.glsc.ngateway.common.api.oaflow.dto.SynOaDigitalKeyDto;
import com.glsc.ngateway.common.api.oaflow.dto.SynOaDigitalKeyInfoDto;
import com.glsc.ngateway.common.api.oaflow.dto.SynOaTradeSeatDto;
import com.glsc.ngateway.common.api.oaflow.dto.SynOaTradeSeatInfoDto;
import com.glsc.ngateway.common.api.common.enums.Constant;
import com.glsc.ngateway.common.api.common.enums.DictConstant;
import com.glsc.ngateway.common.base.domain.mysql.gateway.other.*;
import com.glsc.ngateway.common.base.domain.mysql.gateway.platform.User;
import com.glsc.ngateway.common.api.platform.dto.other.DigitalKeyDto;
import com.glsc.ngateway.common.base.domain.mysql.opmanagemain.task.TaskInfo;
import com.glsc.ngateway.common.base.repo.mysql.gateway.other.*;
import com.glsc.ngateway.opmanage.config.RabbitMQConfig;
import com.glsc.ngateway.opmanage.enums.TaskTypeUrlEnum;
import com.glsc.ngateway.opmanage.service.MailService;
import com.glsc.ngateway.opmanage.service.SystemConfigService;
import com.glsc.ngateway.opmanage.service.archive.ArchiveService;
import com.glsc.ngateway.opmanage.service.feign.GatewayFeignService;
import com.glsc.ngateway.opmanage.service.other.DigitalKeyService;
import com.glsc.ngateway.opmanage.service.other.MessageService;
import com.glsc.ngateway.opmanage.service.other.TradeSeatHistoryService;
import com.glsc.ngateway.opmanage.service.other.TradeSeatRentService;
import com.glsc.ngateway.opmanage.service.task.TaskInfoService;
import com.glsc.ngateway.opmanage.utils.MqUtil;
import com.glsc.ngateway.opmanage.utils.RequestTool;
import com.google.common.collect.ImmutableList;
import com.rabbitmq.client.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.transaction.Transactional;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

@Component
@Transactional
public class SyncOaReceiver {
    private static final Logger logger = LoggerFactory.getLogger(SyncOaReceiver.class);

    @Resource
    private MessageService messageService;

    @Resource
    private SystemConfigService systemConfigService;

//    @Resource
//    private ProdSeriesService prodSeriesService;

    @Resource
    private MailService mailService;

    @Resource
    private GatewayFeignService gatewayFeignService;
//
//    @Resource
//    private GlamCalendarService glamCalendarService;
//
//    @Resource
//    private SaleAgencyService saleAgencyService;
//
//    @Resource
//    private DocumentInfoService documentInfoService;
//
//    @Resource
//    private NoProdContractSignRefService noProdContractSignRefService;
//
//    @Resource
//    private ProdRelationInvestManagerService prodRelationInvestManagerService;

    @Resource
    private TradeSeatHistoryService tradeSeatHistoryService;

    @Resource
    private DigitalKeyService digitalKeyService;

    @Resource
    private TradeSeatRentService tradeSeatRentService;

    @Resource
    private TradeAccountHistoryRepository tradeAccountHistoryRepository;

    @Resource
    private TradeAccountShareHolderRepository tradeAccountShareHolderRepository;

    @Resource
    private TradeAccountOwnFundRepository tradeAccountOwnFundRepository;

    @Resource
    private TradeAccountSaleFundRepository tradeAccountSaleFundRepository;

    @Resource
    private TradeAccountFurtureRepository tradeAccountFurtureRepository;

    @Resource
    private ArchiveService archiveService;

    @Resource
    private TaskInfoService taskInfoService;

    private static final String OA_REVIEW_NODE_NAME_FORCE_END = "强制归档";
    private static final String OA_REVIEW_NODE_NAME_END = "结束";
    private static final String OA_REVIEW_NODE_NAME_9_REVIEW = "公司相关部门委员发表意见";
    private static final String OA_REVIEW_NODE_NAME_PROD_MANAGER_START_REVIEW = "产品经理提起评审";
    private static final String OA_REVIEW_NODE_NAME_PROD_MANAGER_SUBMIT_UPDATE = "产品经理提交更新材料";

    private static final String OA_REVIEW_NODE_STATUS_TYPE = "3";


    private static final String TRADE_ACCOUNT_SET_UP = "0";
    private static final String TRADE_ACCOUNT_MODIFY = "1";
    private static final String TRADE_ACCOUNT_DROP = "2";

    private static final String TRADE_ACCOUNT_TYPE_FURTURE = "期货账户";//期货
    private static final String TRADE_ACCOUNT_TYPE_OWN_FUND = "直销基金账户";//自营基金
    private static final String TRADE_ACCOUNT_TYPE_SALE_FUND = "基金代销平台";//代理基金
    private static final List<String> TRADE_ACCOUNT_TYPE_SHARE_HOLDER = ImmutableList.of("A股账户", "B股账户", "港股通账户", "债券账户", "期权账户", "两融账户", "转融通账户"); //股票
    /*流程节点状态（实际仅中文名称）
    1.发起人
    2.资管产品委委员发表意见
    3.发起人回复意见
    4.资管产品委委员确认意见
    5.资管部负责人
    6.发起人更新材料
    8.内控部审核
    9.公司相关部门委员发表意见
    10.发起人回复意见
    11.公司相关部门委员确认意见
    12.结束
    */
    /*
     * 查询OA表单数据返回样例：
     * {"requestId":"621896","description":"success","workflowName":"（2021-85）国联悦享优选/尊选/精选系列FOF单一资产管理计划变更评审","workflowId":"174103"},SynOaReviewStatusDto(workflowId=174103, requestId=621896, productSelect=1002426, flowStatusType=1, flowStatus=null, reviewerReplyCode=1, reviewerReply=表决已全票“同意", depReviewerReplyCode=null, depReviewerReply=null, businessTypeCode=0, businessType=单一非标类, flowNodeCode=196946, flowNode=资管部负责人)
     * */

    /**
     * JSON格式：workflowId:111,requestId:123456789,workflowName:测试流程标题,description:success
     * //OA评审流程接口返回数据情况：
     * //(productSelect=1000223, flowStatusCode=1, flowStatus=资管产品委委员确认意见, reviewerReplyCode=0, reviewerReply=发起人意见落实回复)
     * //(productSelect=1000223, flowStatusCode=1, flowStatus=发起人更新材料, reviewerReplyCode=0, reviewerReply=发起人意见落实回复)
     * //(productSelect=1000223, flowStatusCode=3, flowStatus=结束, reviewerReplyCode=0, reviewerReply=发起人意见落实回复)
     * //(productSelect=1000224, flowStatusCode=1, flowStatus=资管部负责人, reviewerReplyCode=1, reviewerReply=表决已全票“同意")11
     */
    @RabbitListener(queues = {RabbitMQConfig.AMPRODUCT_QUEUE_OA_WORKFLOW_REMIND})
    @RabbitHandler
    public void processMessage(org.springframework.amqp.core.Message messageObject, Channel channel) throws IOException {
        try {


            boolean ackFlag = true;
            Exception exception = null;

            String message = new String(messageObject.getBody());
            logger.info("AMPRODUCT_QUEUE_SYNC_OA_FORM_DATA，收到消息，message receiver:" + message);

            Message bean = new Message();
            bean.setMsgType(DictConstant.MSG_TYPE_SYNC);
            bean.setMsgContent(message);
            bean.setMsgStatus(DictConstant.MSG_STATUS_SUCCESS);
            bean.setMsgSender(RequestTool.getLocalHost());
            messageService.saveMessage(bean);


            //流程节点变化，获取事件通知时，主动延迟再去获取表单数据，待网关延迟功能上线后，此处不需要再延迟消费
            try {
                Thread.sleep(5 * 1000);//
            } catch (InterruptedException e) {
                logger.error("流程节点变化，获取事件通知时，主动延迟再去获取表单数据sleep失败", e);
            }
            //end of===========================

            JSONObject msgJsonObject = JSONObject.parseObject(message);
            //这两个字段不能为空
            String workflowId = StrUtil.trim(msgJsonObject.getString("workflowId"));
            String requestId = StrUtil.trim(msgJsonObject.getString("requestId"));
            String workflowName = StrUtil.trim(msgJsonObject.getString("workflowName"));

            logger.info("开始进行 查询流程表单数据,workflowId=" + workflowId + ",requestId=" + requestId + ",workflowName=" + workflowName);

            String syncOaFormDataTradeSeat = systemConfigService.findConfigValueByCode(Constant.CONFIG_KEY_SYNC_OA_FORM_DATA_TRADE_SEAT);
            String syncOaFormDataDigitalKeyWorkFlowIdList = systemConfigService.findConfigValueByCode(Constant.CONFIG_KEY_SYNC_OA_FORM_DATA_DIGITAL_KEY_WORKFLOWID_LIST);
            String syncOaFormDataArchiveKeyWorkFlowIdList = systemConfigService.findConfigValueByCode(Constant.SYNC_OA_FORM_DATA_ARCHIVE_KEY_WORKFLOWID_LIST);
            String syncOaFormDataTradeAccount = systemConfigService.findConfigValueByCode(Constant.CONFIG_KEY_SYNC_OA_FORM_DATA_TRADE_ACCOUNT);
            String syncOaFormDataXinYiWorkFlowIdList = systemConfigService.findConfigValueByCode(Constant.CONFIG_KEY_SYNC_OA_FORM_DATA_XIN_YI_WORK_FLOW_ID);
            try {
                if (StrUtil.isNotEmpty(syncOaFormDataTradeSeat) && syncOaFormDataTradeSeat.contains(workflowId)) {
                    syncOaTradeSeat(workflowId, requestId);
                } else if (StrUtil.isNotEmpty(syncOaFormDataDigitalKeyWorkFlowIdList) && syncOaFormDataDigitalKeyWorkFlowIdList.contains(workflowId)) {
                    syncOaDigitalKey(workflowId, requestId);
                } else if (StrUtil.isNotEmpty(syncOaFormDataTradeAccount) && syncOaFormDataTradeAccount.contains(workflowId)) {
                    syncOaTradeAccount(workflowId, requestId);
                } else if (StrUtil.isNotEmpty(syncOaFormDataArchiveKeyWorkFlowIdList) && syncOaFormDataArchiveKeyWorkFlowIdList.contains(workflowId)) {
                    //档案系统同步oa流程文件用-暂停同步
                    //archiveService.autoDownLoadOperateMattersOaFile(requestId);
                } else if (StrUtil.isNotEmpty(syncOaFormDataXinYiWorkFlowIdList) && syncOaFormDataXinYiWorkFlowIdList.contains(workflowId)) {
                    syncOaXinYi(workflowId, requestId);
                }

            } catch (Exception e) {
                ackFlag = false;
                exception = e;
                logger.error("收到同步OA表单数据消息，处理异常：", e);
                TaskInfo task = TaskInfo.builder().build();
                if (StrUtil.isNotEmpty(syncOaFormDataTradeSeat) && syncOaFormDataTradeSeat.contains(workflowId)) {
                    //syncOaTradeSeat(workflowId, requestId);
                    task.setType(TaskTypeUrlEnum.OA_TRADE_SEAT.getType());
                    task.setRoleCode(TaskTypeUrlEnum.OA_TRADE_SEAT.getRoleCode());
                } else if (StrUtil.isNotEmpty(syncOaFormDataDigitalKeyWorkFlowIdList) && syncOaFormDataDigitalKeyWorkFlowIdList.contains(workflowId)) {
                    //syncOaDigitalKey(workflowId, requestId);
                    task.setType(TaskTypeUrlEnum.OA_DIGITAL_KEY.getType());
                    task.setRoleCode(TaskTypeUrlEnum.OA_DIGITAL_KEY.getRoleCode());
                } else if (StrUtil.isNotEmpty(syncOaFormDataTradeAccount) && syncOaFormDataTradeAccount.contains(workflowId)) {
                    //syncOaTradeAccount(workflowId, requestId);
                    task.setType(TaskTypeUrlEnum.OA_TRADE_ACCOUNT.getType());
                    task.setRoleCode(TaskTypeUrlEnum.OA_TRADE_ACCOUNT.getRoleCode());
                }
                task.setName("[OA同步异常]-" + workflowName);
                task.setCreateTime(new Date());
                task.setStatus("0");


                taskInfoService.saveTaskInfo(task);
            }
            //消息发送是否异常,ackFlag=false，注意：网关的OA通知队列没有增加死信队列支持
            MqUtil.processAckFlag(messageObject, channel, ackFlag, "同步OA表单数据处理", exception);
        } catch (Exception e) {
            logger.error("AMPRODUCT_QUEUE_SYNC_OA_FORM_DATA，收到消息，处理异常：", e);
        }
    }


    private void syncOaXinYi(String workflowId, String requestId) throws Exception {
        gatewayFeignService.syncOaXinYiFormData4XinYi(workflowId, requestId);

    }

    /**
     * 处理自有资金交易账户开立、变更、注销流程
     *
     * @param workflowId
     * @param requestId
     */
    private void syncOaTradeAccount(String workflowId, String requestId) {
        TradeAccountHistory tradeAccount = gatewayFeignService.getOATradeAccount(workflowId, requestId);
        if (!OA_REVIEW_NODE_STATUS_TYPE.equals(tradeAccount.getFlowStatusType()) || (OA_REVIEW_NODE_STATUS_TYPE.equals(tradeAccount.getFlowStatusType()) && OA_REVIEW_NODE_NAME_FORCE_END.equals(tradeAccount.getFlowNode()))) {//交易单元相关业务流程尚未结束，不能进行交易单元信息处理
            logger.info("交易账号相关业务流程尚未结束，不能进行交易账号信息同步处理，tradeAccount=" + tradeAccount);
            return;
        }
        logger.info("同步OA表单交易账号信息处理，tradeAccount：" + tradeAccount);
        switch (tradeAccount.getBusinessTypeCode()) {
            case TRADE_ACCOUNT_SET_UP:
                tradeAccountHistoryRepository.save(tradeAccount);
                if (TRADE_ACCOUNT_TYPE_SHARE_HOLDER.contains(tradeAccount.getAccountType()) && CollectionUtil.isNotEmpty(tradeAccount.getShareHolderList())) {
                    //存在相同的记录先要标记为删除
                    tradeAccountShareHolderRepository.updateDataStatusByShareHolderAccounts(tradeAccount.getShareHolderList().stream().map(TradeAccountShareHolder::getShareHolderAccount).collect(Collectors.toList()));
                    tradeAccountShareHolderRepository.saveAll(tradeAccount.getShareHolderList());
                } else if (tradeAccount.getAccountType().equals(TRADE_ACCOUNT_TYPE_OWN_FUND) && CollectionUtil.isNotEmpty(tradeAccount.getOwnFundList())) {
                    tradeAccountOwnFundRepository.saveAll(tradeAccount.getOwnFundList());
                } else if (tradeAccount.getAccountType().equals(TRADE_ACCOUNT_TYPE_SALE_FUND) && CollectionUtil.isNotEmpty(tradeAccount.getSaleFundList())) {
                    tradeAccountSaleFundRepository.saveAll(tradeAccount.getSaleFundList());
                } else if (tradeAccount.getAccountType().equals(TRADE_ACCOUNT_TYPE_FURTURE) && CollectionUtil.isNotEmpty(tradeAccount.getFurtureList())) {
                    tradeAccountFurtureRepository.saveAll(tradeAccount.getFurtureList());
                }
                break;
            case TRADE_ACCOUNT_MODIFY:
                //修改和注销不开发--肖丹
                break;
            case TRADE_ACCOUNT_DROP:
                //修改和注销不开发--肖丹
                break;
            default:
                throw new IllegalArgumentException("BusinessTypeCode错误");
        }
    }

    /**
     * 同步OA表单交易单元相关信息处理
     *
     * @param workflowId
     * @param requestId
     * @throws Exception
     */
    @Transactional
    public void syncOaTradeSeat(String workflowId, String requestId) throws Exception {
        SynOaTradeSeatDto synOaTradeSeatDto = gatewayFeignService.getOAFormData4TradeSeat(workflowId, requestId);
        if (!OA_REVIEW_NODE_STATUS_TYPE.equals(synOaTradeSeatDto.getFlowStatusType()) || (OA_REVIEW_NODE_STATUS_TYPE.equals(synOaTradeSeatDto.getFlowStatusType()) && OA_REVIEW_NODE_NAME_FORCE_END.equals(synOaTradeSeatDto.getFlowNode()))) {//交易单元相关业务流程尚未结束，不能进行交易单元信息处理
            logger.info("交易单元相关业务流程尚未结束，不能进行交易单元信息同步处理，synOaTradeSeatDto=" + synOaTradeSeatDto);
            return;
        }
        logger.info("同步OA表单交易单元信息处理，synOaTradeSeatDto：" + synOaTradeSeatDto);
        if (synOaTradeSeatDto != null && CollectionUtil.isNotEmpty(synOaTradeSeatDto.getTradeSeatInfoList())) {
            List<TradeSeatHistory> toDoSavedTradeSeatHistoryList = new ArrayList();
            List<SynOaTradeSeatInfoDto> tradeSeatInfoList = synOaTradeSeatDto.getTradeSeatInfoList();
            for (SynOaTradeSeatInfoDto item : tradeSeatInfoList) {
                TradeSeatHistory tradeSeatHistory = new TradeSeatHistory();

                BeanUtil.copyProperties(item, tradeSeatHistory);
                BeanUtil.copyProperties(synOaTradeSeatDto, tradeSeatHistory);

                tradeSeatHistory.setOaRequestId(synOaTradeSeatDto.getRequestId());//字段名不匹配，需要手工指定
                tradeSeatHistory.setDataSource(DictConstant.TRADE_SEAT_SOURCE_AUTO);

                toDoSavedTradeSeatHistoryList.add(tradeSeatHistory);
            }
            logger.info("同步OA表单交易单元信息变更信息处理，待保存交易单元列表信息：" + toDoSavedTradeSeatHistoryList);
            if (CollectionUtils.isEmpty(toDoSavedTradeSeatHistoryList)) {
                return;
            } else {
                tradeSeatHistoryService.saveTradeSeatHistoryList(toDoSavedTradeSeatHistoryList);

                for (TradeSeatHistory tradeSeatHistory : toDoSavedTradeSeatHistoryList) {
                    tradeSeatRentService.saveOrUpdateFromRentHistory(tradeSeatHistory);
                    logger.info("从交易单元OA流水中，更新交易单元信息：{}-{}", tradeSeatHistory.getTradeSeatCode()
                            , tradeSeatHistory.getTradeSeatMarket());
                }

            }
        }
    }

    /**
     * 同步OA表单数字证书相关信息处理
     *
     * @param workflowId
     * @param requestId
     * @throws Exception
     */
    @Transactional
    public void syncOaDigitalKey(String workflowId, String requestId) throws Exception {
        SynOaDigitalKeyDto synOaDigitalKeyDto = gatewayFeignService.getOAFormData4Digital(workflowId, requestId);
        if (!OA_REVIEW_NODE_STATUS_TYPE.equals(synOaDigitalKeyDto.getFlowStatusType()) || (OA_REVIEW_NODE_STATUS_TYPE.equals(synOaDigitalKeyDto.getFlowStatusType()) && OA_REVIEW_NODE_NAME_FORCE_END.equals(synOaDigitalKeyDto.getFlowNode()))) {//数字证书相关业务流程尚未结束，不能进行数字证书信息处理
            logger.info("数字证书相关业务流程尚未结束，不能进行数字证书信息同步处理，synOaDigitalKeyDto=" + synOaDigitalKeyDto);
            return;
        }

        logger.info("同步OA表单数字证书信息处理，synOaDigitalKeyDto：" + synOaDigitalKeyDto);
        if (synOaDigitalKeyDto != null && CollectionUtil.isNotEmpty(synOaDigitalKeyDto.getDigitalKeyInfoDtoList())) {
            if ("0".equals(synOaDigitalKeyDto.getFlowTypeCode())) {//新增数字证书
                List<SynOaDigitalKeyInfoDto> synOaDigitalKeyInfoDtoList = synOaDigitalKeyDto.getDigitalKeyInfoDtoList();
                logger.info("同步OA表单数字证书新增流程处理，待保存数字证书列表信息：" + synOaDigitalKeyInfoDtoList);

                for (SynOaDigitalKeyInfoDto item : synOaDigitalKeyInfoDtoList) {
                    DigitalKeyDto digitalKeyDto = new DigitalKeyDto();

                    BeanUtil.copyProperties(item, digitalKeyDto);
                    BeanUtil.copyProperties(synOaDigitalKeyDto, digitalKeyDto);
                    if (StrUtil.isNotEmpty(item.getRemark())) {
                        digitalKeyDto.setRemark(item.getRemark());
                    }

                    digitalKeyDto.setCustodianList(item.getCustodianAccount());
                    try {
                        User admin = new User();
                        admin.setUsername(Constant.USER_ADMIN);
                        admin.setName(Constant.USER_ADMIN_NAME);
                        digitalKeyService.save(digitalKeyDto, requestId, admin);
                    } catch (Exception e) {
                        String errMsg = "同步OA表单数字证书新增到本地数据库异常：" + e.getMessage();
                        logger.error(errMsg, e);
                        mailService.sendMailToAdmin("数字证书新增同步失败", errMsg);
                    }
                }
            } else if ("1".equals(synOaDigitalKeyDto.getFlowTypeCode())) {//修改数字证书信息
                List<SynOaDigitalKeyInfoDto> synOaDigitalKeyInfoDtoList = synOaDigitalKeyDto.getDigitalKeyInfoDtoList();

                Map<String, SynOaDigitalKeyInfoDto> synOaDigitalKeyInfoDtoMap = new HashMap<>();
                for (SynOaDigitalKeyInfoDto digitalKey : synOaDigitalKeyInfoDtoList) {
                    String uniqueKeyID = String.format("%s_%s", digitalKey.getKeyIssueBranch(), digitalKey.getKeyNo());
                    synOaDigitalKeyInfoDtoMap.put(uniqueKeyID, digitalKey);
                }

                List<String> branchAndKeyNoList = synOaDigitalKeyInfoDtoMap.keySet().stream().collect(Collectors.toList());
                List<DigitalKey> toDoSavedDigitalKeyHistoryList = digitalKeyService.findByBranAndKeyNoList(branchAndKeyNoList);
                logger.info("同步OA表单数字证书修改流程处理，待保存数字证书列表信息：" + toDoSavedDigitalKeyHistoryList);

                if (CollectionUtil.isNotEmpty(toDoSavedDigitalKeyHistoryList)) {
                    toDoSavedDigitalKeyHistoryList.forEach(item -> {
                        String uniqueKeyID = String.format("%s_%s", item.getKeyIssueBranch(), item.getKeyNo());
                        SynOaDigitalKeyInfoDto synOaDigitalKeyInfoDto = synOaDigitalKeyInfoDtoMap.get(uniqueKeyID);

                        BeanUtil.copyProperties(synOaDigitalKeyInfoDto, item);
                        BeanUtil.copyProperties(synOaDigitalKeyDto, item);

                        DigitalKeyDto digitalKeyDto = new DigitalKeyDto();
                        BeanUtil.copyProperties(item, digitalKeyDto);
                        if (StrUtil.isNotEmpty(item.getRemark())) {
                            digitalKeyDto.setRemark(item.getRemark());
                        }
                        digitalKeyDto.setCustodianList(synOaDigitalKeyInfoDto.getCustodianAccount());
                        User admin = new User();
                        admin.setUsername(Constant.USER_ADMIN);
                        admin.setName(Constant.USER_ADMIN_NAME);
                        digitalKeyService.update(digitalKeyDto, requestId, admin);
                    });
                }
            } else if ("2".equals(synOaDigitalKeyDto.getFlowTypeCode())) {//数字证书到期日延期
                List<SynOaDigitalKeyInfoDto> synOaDigitalKeyInfoDtoList = synOaDigitalKeyDto.getDigitalKeyInfoDtoList();

                Map<String, SynOaDigitalKeyInfoDto> synOaDigitalKeyInfoDtoMap = new HashMap<>();
                for (SynOaDigitalKeyInfoDto digitalKey : synOaDigitalKeyInfoDtoList) {
                    String uniqueKeyID = String.format("%s_%s", digitalKey.getKeyIssueBranch(), digitalKey.getKeyNo());
                    synOaDigitalKeyInfoDtoMap.put(uniqueKeyID, digitalKey);
                }

                Set<String> dealedUniqueKeyIDSet = new HashSet<>();

                List<String> branchAndKeyNoList = synOaDigitalKeyInfoDtoMap.keySet().stream().collect(Collectors.toList());
                List<DigitalKey> toDoSavedDigitalKeyHistoryList = digitalKeyService.findByBranAndKeyNoList(branchAndKeyNoList);
                if (CollectionUtil.isNotEmpty(toDoSavedDigitalKeyHistoryList)) {
                    toDoSavedDigitalKeyHistoryList.forEach(item -> {
                        String uniqueKeyID = String.format("%s_%s", item.getKeyIssueBranch(), item.getKeyNo());
                        SynOaDigitalKeyInfoDto synOaDigitalKeyInfoDto = synOaDigitalKeyInfoDtoMap.get(uniqueKeyID);
                        item.setKeyExpireDate(synOaDigitalKeyInfoDto.getKeyExpireDate());//延期的只修改到期日

                        DigitalKeyDto digitalKeyDto = new DigitalKeyDto();
                        BeanUtil.copyProperties(item, digitalKeyDto);
                        if (StrUtil.isNotEmpty(item.getRemark())) {
                            digitalKeyDto.setRemark(item.getRemark());
                        }
                        digitalKeyDto.setCustodianList(synOaDigitalKeyInfoDto.getCustodianAccount());
                        digitalKeyDto.setHasRemind(DictConstant.NO);//到期提醒标识关闭
                        User admin = new User();
                        admin.setUsername(Constant.USER_ADMIN);
                        admin.setName(Constant.USER_ADMIN_NAME);
                        digitalKeyService.update(digitalKeyDto, requestId, admin);
                        dealedUniqueKeyIDSet.add(uniqueKeyID);
                    });
                }
                //todo 处理在到期提醒中新增的数字证书信息，对于此类信息做新增
                if (CollectionUtil.isNotEmpty(synOaDigitalKeyInfoDtoMap)) {
                    for (String key : synOaDigitalKeyInfoDtoMap.keySet()) {
                        if (!dealedUniqueKeyIDSet.contains(key)) {
                            //在表中不存在，需要新增
                            SynOaDigitalKeyInfoDto item = synOaDigitalKeyInfoDtoMap.get(key);

                            DigitalKeyDto digitalKeyDto = new DigitalKeyDto();

                            BeanUtil.copyProperties(item, digitalKeyDto);
                            BeanUtil.copyProperties(synOaDigitalKeyDto, digitalKeyDto);
                            if (StrUtil.isNotEmpty(item.getRemark())) {
                                digitalKeyDto.setRemark(item.getRemark());
                            }

                            digitalKeyDto.setCustodianList(item.getCustodianAccount());
                            try {
                                User admin = new User();
                                admin.setUsername(Constant.USER_ADMIN);
                                admin.setName(Constant.USER_ADMIN_NAME);
                                digitalKeyService.save(digitalKeyDto, requestId, admin);
                            } catch (Exception e) {
                                String errMsg = "同步OA表单数字证书延期新增到本地数据库异常：" + e.getMessage();
                                logger.error(errMsg, e);
                                mailService.sendMailToAdmin("数字证书延期新增同步失败", errMsg);
                            }
                        }
                    }
                }

                logger.info("同步OA表单数字证书到期提醒流程处理，待保存数字证书列表信息：" + toDoSavedDigitalKeyHistoryList);
                if (CollectionUtil.isNotEmpty(toDoSavedDigitalKeyHistoryList)) {
                    digitalKeyService.saveDigitalKeyList(toDoSavedDigitalKeyHistoryList);
                }
            }
        }
    }

    /**
     * 流程实例Id合并
     *
     * @param existRequestIdStr 现有流程实例字符串，多个逗号分割
     * @param newRequestId      新流程实例Id
     * @return
     */
    public String mergeRequestIdList(String existRequestIdStr, String newRequestId) {
        String mergeRequestIdStr = null;
        if (StrUtil.isEmpty(existRequestIdStr)) {
            mergeRequestIdStr = newRequestId == null ? "" : StrUtil.trim(newRequestId);
        } else {
            List<String> existRequestIdList = Arrays.asList(existRequestIdStr.split(","));
            if (!existRequestIdList.contains(newRequestId)) {
                existRequestIdList.add(newRequestId);
            }

            mergeRequestIdStr = String.join(",", existRequestIdList);
        }

        if (StrUtil.isEmpty(mergeRequestIdStr)) {
            mergeRequestIdStr = "";
        }

        return mergeRequestIdStr;
    }
}
